package com.wedimob.html;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import android.content.Context;
import android.net.ConnectivityManager;
import android.util.Log;

import com.google.gson.Gson;

public class HtmlTools {

    private static final String CLASS_TAG = HtmlTools.class.getName();

    private static String exceptionMsg(Exception e) {
        if (e.getCause() != null && e.getCause().getMessage() != null)
            return e.getCause().getMessage();
        
        if ( e.getMessage() != null )
            return e.getMessage();
        
        return "Unknown error";
    }

    public static HTMLPage post(String url, Form form, HttpClient httpclient,
            HttpContext context) {
        if (!"post".equals(form.getMethod().toLowerCase(Locale.US)))
            throw new RuntimeException("form is not a post action");

        try {
            synchronized (httpclient) {
                HttpPost httppost;
                String action = form.getAction();
                if (action == null || "".equals(action))
                    httppost = new HttpPost(form.origin());
                else
                    httppost = new HttpPost(generateURL(url, form.getAction(),
                            null).toString());

                httppost.setHeader(
                        "User-Agent",
                        "Mozilla/5.0 (X11; U; Linux "
                                + "i686; en-US; rv:1.8.1.6) Gecko/20061201 Firefox/2.0.0.6 (Ubuntu-feisty)");
                httppost.setHeader(
                        "Accept",
                        "text/html,application/xml,"
                                + "application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
                httppost.setHeader("Content-Type",
                        "application/x-www-form-urlencoded");

                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                Iterator<FormField> fieldsIterator = form.fields();
                while (fieldsIterator.hasNext()) {
                    FormField field = fieldsIterator.next();
                    if (field.getType() == FormFieldType.CHECKBOX) {
                        if ("true".equals(field.getValue()))
                            nameValuePairs.add(new BasicNameValuePair(field
                                    .getName(), "on"));
                    } else {
                        nameValuePairs.add(new BasicNameValuePair(field.getName(),
                                field.getValue()));
                    }
                }
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                httppost.addHeader("Referer", form.origin());
                HttpResponse response = httpclient.execute(httppost, context);
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        response.getEntity().getContent()));

                String thisLine;
                StringBuilder result = new StringBuilder();
                while ((thisLine = reader.readLine()) != null) {
                    result.append(thisLine);
                }
                return new HTMLPage(httppost.getURI().toString(), response.getStatusLine(),
                        response.getAllHeaders(), result.toString());
            }
        } catch (Exception e) {
            Log.e(CLASS_TAG, exceptionMsg(e));
            throw new RuntimeException(exceptionMsg(e));
        }
    }

    public static HTMLPage get(URL url, HttpClient httpclient,
            HttpContext context) {
        try {
            synchronized (httpclient) {
                HttpGet httpget = new HttpGet(url.toString());
                httpget.setHeader(
                        "User-Agent",
                        "Mozilla/5.0 (X11; U; Linux "
                                + "i686; en-US; rv:1.8.1.6) Gecko/20061201 Firefox/2.0.0.6 (Ubuntu-feisty)");
                httpget.setHeader(
                        "Accept",
                        "text/html,application/xml,"
                                + "application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
                httpget.setHeader("Content-Type",
                        "application/x-www-form-urlencoded");
                httpget.addHeader("Referer", url.toString());
                HttpResponse response = httpclient.execute(httpget, context);
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        response.getEntity().getContent()));

                String thisLine;
                StringBuilder result = new StringBuilder();
                while ((thisLine = reader.readLine()) != null) {
                    result.append(thisLine);
                }
                return new HTMLPage(httpget.getURI().toString(), response.getStatusLine(),
                        response.getAllHeaders(), result.toString());
            }
        } catch (Exception e) {
            Log.e(CLASS_TAG, exceptionMsg(e));
            throw new RuntimeException(exceptionMsg(e));
        }
    }

    public static List<Form> extractForm(HTMLPage html) {
        List<Form> result = new ArrayList<Form>();
        Document doc = Jsoup.parse(html.getBody());
        Elements forms = doc.select("form");
        int index = 0;
        for (Element form : forms) {
            String name = form.attr("id");
            if (name == null || "".equals(name))
                name = form.attr("class");
            String method = form.attr("method");
            String action = form.attr("action");
            Form formObj = new Form(html.getUrl(), name != null ? name : "" + index++, method,
                    action);
            Elements inputs = form.select("input");
            for (Element input : inputs) {
                name = input.attr("name");
                if (name == null)
                    continue;

                String type = input.attr("type");
                String value = input.attr("value");
                if ("text".equals(type)) {
                    formObj.addField(new FormField(FormFieldType.TEXT, name,
                            value));
                } else if ("password".equals(type)) {
                    formObj.addField(new FormField(FormFieldType.PASSWORD,
                            name, value));
                } else if ("hidden".equals(type)) {
                    formObj.addField(new FormField(FormFieldType.HIDDEN, name,
                            value));
                } else if ("submit".equals(type)) {
                    formObj.addField(new FormField(FormFieldType.SUBMIT, name,
                            value));
                } else if ("button".equals(type)) {
                    formObj.addField(new FormField(FormFieldType.BUTTON, name,
                            value));
                } else if ("checkbox".equals(type)) {
                    value = input.outerHtml().contains(" checked") ? "true"
                            : "false";
                    formObj.addField(new FormField(FormFieldType.CHECKBOX,
                            name, value));
                } else {
                    throw new RuntimeException("Unknown type " + type);
                }

            }
            Elements selects = form.select("select");
            for (Element select : selects) {
                name = select.attr("name");
                Elements options = select.select("option");
                FormField selectObject = new FormField(FormFieldType.SELECT,
                        name, null);
                for (Element option : options) {
                    String value = option.attr("value");
                    String label = option.text();
                    if (option.outerHtml().contains(" selected")) {
                        selectObject.setValue(value);
                    }
                    selectObject.addSelectValue(value, label);
                }
                formObj.addField(selectObject);
            }
            Elements textareas = form.select("textarea");
            for (Element textarea : textareas) {
                name = textarea.attr("name");
                String text = textarea.text();
                formObj.addField(new FormField(FormFieldType.TEXTAREA, name,
                        text));
            }

            result.add(formObj);
        }
        return result;
    }

    public static URL generateURL(String url, String page,
            Map<String, String> params) {
        StringBuilder pagewithparams = new StringBuilder();
        pagewithparams.append(page);
        if (params != null) {
            int i = 0;
            for (String key : params.keySet()) {
                pagewithparams.append(i > 0 ? "&" : "?");
                pagewithparams.append(key);
                pagewithparams.append("=");
                pagewithparams.append(params.get(key));
                i++;
            }
        }

        try {
            return new URL("http", url, pagewithparams.toString());
        } catch (Exception e) {
            Log.e(CLASS_TAG, exceptionMsg(e));
            throw new RuntimeException(exceptionMsg(e));
        }
    }

    static private class WhatIsMyIPResponse {
        public String ip;
        @SuppressWarnings("unused")
        public double elapsedTime;
    }

    public static String getClientIp() {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpContext localContext = new BasicHttpContext();
        String url = "http://server.elouadi.biz/app/freebox.php";
        Form form = new Form(url, null, "post", null);
        form.addField(new FormField(FormFieldType.HIDDEN, "action", "whatismyip"));
        HTMLPage response = post(url, form, httpClient, localContext);
        Gson gson = new Gson();
        WhatIsMyIPResponse serverResponse = gson.fromJson(response.getBody(), WhatIsMyIPResponse.class);
        return serverResponse.ip;
    }

    public static boolean isOnline(Context context) {
        ConnectivityManager cm =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        return cm.getActiveNetworkInfo() != null &&
                cm.getActiveNetworkInfo().isConnectedOrConnecting();
    }
}
